import asyncio
import functools
from typing import Optional, Callable

import fastapi
from fastapi import Depends, FastAPI
import uvicorn

app = FastAPI()


class A:
    pass


def get_cur_name():
    return '张三'


# 这里传入了name参数，不管是写在哪里都是需要验证表单参数的
async def common_parameters(name, q: Optional[str] = None, skip: int = 0, limit: int = 100):
    return {"q": q, "skip": skip, "limit": limit}


@app.get("/items/")
async def read_items(commons: dict = Depends(common_parameters)):
    return commons


# 当写在path的时侯， 也会去校验dependencies
# 和函数上的参数的Depends不一样的是，写在函数里就会变为形参
@app.get("/users", dependencies=[Depends(common_parameters), Depends(get_cur_name)])
async def read_users():
    return {}


@app.get("/db")
async def db(name: str = Depends(get_cur_name)):
    return {
        'name': name
    }


class AppSettings(object):
    name = 'Tom'


def get_app_settings() -> AppSettings:
    return AppSettings()


class User(object):
    def __init__(self, name):
        self.name = name


async def parse_header(name: str) -> User:
    await asyncio.sleep(1)
    if name != 'baloneo':
        raise fastapi.HTTPException(fastapi.status.HTTP_403_FORBIDDEN, detail='用户验证失败')
    try:
        yield User(name)
    finally:
        print('over User')


def get_current_user(is_admin=False) -> Callable:
    # await asyncio.sleep(0.5)
    return parse_header


# 除非继承自 pydantic ， 否则user: User, 会报valid pydantic field type错
@app.get("/deep_depends")
async def deep_depends(user: User = Depends(get_current_user(is_admin=True)), name=1,
                       settings: AppSettings = Depends(get_app_settings)):
    print('over...')
    return {
        'name': settings.name,
        'user': user.name
    }


# include_in_schema在api文档中隐藏
@app.get("/deep_depends2", include_in_schema=False)
async def deep_depends(user: User = Depends(functools.partial(parse_header, 'baloneo')), name=1,
                       settings: AppSettings = Depends(get_app_settings)):
    print('over...')
    return {
        'name': settings.name,
        'user': user.name
    }


if __name__ == '__main__':
    uvicorn.run('__main__:app', port=9999, reload=True)
